// expression_pair.hh
// a pair of time-series expression vector
// (c) Yongjin Park, 2013
#ifndef EXPRESSION_PAIR_HH_
#define EXPRESSION_PAIR_HH_

#include "expression.hh"

////////////////////////////////////////////////////////////////
// expression pair : two vectors x_i and y_i
// for the same gene i with the same length T
struct expr_pair_t
{
  typedef std::vector<double> vec_t;

  explicit expr_pair_t(const int id, const size_t T) :
      id(id), T(T), x(T, 0.), y(T, 0.)
  {
#ifdef DEBUG
    assert_msg(T > 0, "positive size of vector");
#endif
  }

  const int id;
  const size_t T;
  vec_t x;
  vec_t y;
};

// an iterator class for column_x(j) and column_y(j);
template<typename it_t>
struct pair_iterator_t
{
private:

  it_t it;     // row iterator
  int j; // fixed column index

public:

  explicit pair_iterator_t(it_t it, int j) :
      it(it), j(j)
  {
  }

  bool operator ==(const pair_iterator_t& rhs) const
  {
    return (j == rhs.j) && (it == rhs.it);
  }

  bool operator !=(const pair_iterator_t& rhs) const
  {
    return !(*this == rhs);
  }

  pair_iterator_t& operator ++()
  {
    ++it;
    return *this;
  }

  // get_x and get_y
  void get_xy(double& x, double& y)
  {
    x = it->first->x.at(j);
    y = it->first->y.at(j);
  }

  void get_prob(double& z)
  {
    z = it->second;
  }

};

typedef expr_ptr_set_t<expr_pair_t> expr_pair_set_t;
typedef pair_iterator_t<expr_pair_set_t::iterator_t> eps_iterator;

eps_iterator begin(const expr_pair_set_t& pair_set, int j)
{
  return eps_iterator(pair_set.begin(), j);
}

eps_iterator end(const expr_pair_set_t& pair_set, int j)
{
  return eps_iterator(pair_set.end(), j);
}



////////////////////////////////////////////////////////////////
// I/O routines
typedef std::vector<boost::shared_ptr<expr_pair_t> > expr_pair_vec_t;

bool read_expr_pair_vec(const char* x_file, const char* y_file,
    expr_pair_vec_t& out, size_t& n, size_t& p)
{

  n = num_rows(x_file);
  p = num_columns(x_file);

  if (n != num_rows(y_file))
    return false;

  if (p != num_columns(y_file))
    return false;

  out.clear();

  std::ifstream xstr(x_file, std::ios::in);
  std::ifstream ystr(y_file, std::ios::in);

  double x, y;

  int id = -1;
  for (size_t i = 0; (xstr >> x) && (ystr >> y); ++i)
  {
    if ((i % p) == 0)
      out.push_back(boost::shared_ptr<expr_pair_t>(new expr_pair_t(++id, p)));

    size_t pos = i % p;
    expr_pair_t& ep_obj = *(out[id].get());
    ep_obj.x[pos] = x;
    ep_obj.y[pos] = y;
  }

  xstr.close();
  ystr.close();

  if (id != (n - 1))
    return false;

  return true;
}

void vec2set(expr_pair_vec_t& pair_vec, expr_pair_set_t& pair_set)
{
  for (size_t j = 0; j < pair_vec.size(); ++j)
    pair_set.insert(pair_vec.at(j));
}


#endif /* EXPRESSION_PAIR_HH_ */
